package com.ossfk.net.client.adapter;

import java.util.concurrent.TimeUnit;

import com.ossfk.net.config.NetClientConfig;
import com.ossfk.net.session.TcpSession;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class AbstractClientAdapter extends ChannelInboundHandlerAdapter {
	/** 空闲次数 */
	private int idleCount;
	/** 允许的最大空闲次数 */
	private static final int MAX_IDLE_COUNT = 3;
	/** 客户端配置 */
	private NetClientConfig clientConfig;

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		idleCount = 0;
		// 建立连接时
		log.info("Connection successful,remoteAddress:{}", ctx.channel().remoteAddress());
		// 保存session在成功连接后通过list
		super.channelActive(ctx);
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		log.info("Connection is closed,remoteAddress:{}", ctx.channel().remoteAddress());
		// 清空session
		if(clientConfig != null && clientConfig.getClient()!=null) {
			clientConfig.getClient().clearSession();
		}
		if (clientConfig != null && clientConfig.isAutoConnect()) {
			long autoConnectSeconds =  clientConfig.getAutoConnectSeconds();
			log.info("reconnect after {} seconds",autoConnectSeconds);
			final EventLoop eventLoop = ctx.channel().eventLoop();
			eventLoop.schedule(() -> clientConfig.getClient().connect(), autoConnectSeconds, TimeUnit.SECONDS);
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		log.error("Exception caught:{}", cause.getMessage());
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		try {
			TcpSession session= null;
			if(clientConfig != null && clientConfig.getClient()!=null) {
				session = clientConfig.getClient().getSession();
			}
			handleMessage(session,msg);
		} catch (Exception e) {
			log.error("Channel read error:{}", e.getMessage());
		} finally {
			// 释放已经读完的字节
			ReferenceCountUtil.release(msg);
		}
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
			IdleStateEvent event = (IdleStateEvent) evt;
			// 如果读通道处于空闲状态
			if (event.state() == IdleState.READER_IDLE) {
				idleCount++;
				if (idleCount > MAX_IDLE_COUNT) {
					ctx.channel().close();
				}
			}
		} else {
			// 超时处理
			super.userEventTriggered(ctx, evt);
		}
	}

	/**
	 * 
	 * @Description: 消息处理
	 * @param msg
	 * @author Liujiefu
	 * @date 2020-03-16 13:34:55
	 */
	public abstract void handleMessage(TcpSession session,Object msg);

	public NetClientConfig getConfig() {
		return clientConfig;
	}

	public void setConfig(NetClientConfig config) {
		this.clientConfig = config;
	}

}
